package com.sansecy.customview.drawArc;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import androidx.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class FullBarChart extends View {
    private int mHighlightColor;
    private int mDefaultColor;
    private float mItemWidth;
    private boolean mUseAnimation = false;
    /**
     * 条形图之间的间距
     */
    private float mGapWidth;
    private int mGapCount;
    private int mW;
    private int mH;

    private int mSelectPosition;
    private Paint mPaint;
    private Paint mSelectedPaint;
    private TextPaint mTextPaint;
    private int mItemCount;

    public static final int MODE_FIXED = 1;
    public static final int MODE_SCROLLABLE = 0;
    private int mMode;
    private int mGraphHeight;
    private float mContentWidth;
    private int mTextHeight;
    private int mPaddingBottom;
    private int mPaddingTop;
    private int mContentHeight;
    private OnItemBarClickListener mOnItemBarClickListener;
    private int mDefaultSelectedPosition = -1;
    private int mShadowColor = Color.GRAY;
    private boolean mDrawHighlightShadow = false;
    private int mHighlightShadowColor = Color.GRAY;
    private boolean mDrawAllShadow = false;
    private Paint mShadowPaint;
    private int mAnimationDuration = 3000;

    public void setOnItemBarClickListener(OnItemBarClickListener onItemBarClickListener) {
        mOnItemBarClickListener = onItemBarClickListener;
    }

    public FullBarChart(Context context) {
        super(context);
    }

    public FullBarChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);

        mSelectedPaint = new Paint();
        mSelectedPaint.setStyle(Paint.Style.FILL);

        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextSize(dpToPx(12));

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);

        mShadowPaint = new Paint();
        mShadowPaint.setColor(mShadowColor);
        mShadowPaint.setAntiAlias(true);
        mShadowPaint.setStyle(Paint.Style.FILL);

        mMode = MODE_FIXED;
    }

    public void setShadowColor(int shadowColor) {
        mShadowColor = shadowColor;
        mShadowPaint.setColor(mShadowColor);
    }

    public void setDrawHighlightShadow(boolean drawHighlightShadow) {
        mDrawHighlightShadow = drawHighlightShadow;
    }

    public void setHighlightShadowColor(int highlightShadowColor) {
        mHighlightShadowColor = highlightShadowColor;
    }

    public void setDrawAllShadow(boolean drawAllShadow) {
        mDrawAllShadow = drawAllShadow;
    }

    private List<ChartData> mChartData;
    private List<RectF> mRectFS = new ArrayList<>();

    private int mPaddingLeft;

    private int mPaddingRight;
    private int mTextVerticalSpacing;

    public void setHighlightColor(int highlightColor) {
        mHighlightColor = highlightColor;
    }

    public void setDefaultColor(int defaultColor) {
        mDefaultColor = defaultColor;
    }

    public void setTextColor(int textColor) {
        mTextPaint.setColor(textColor);
    }

    public void setChartData(List<ChartData> chartData) {
        if (chartData == null) {
            return;
        }
        mRectFS.clear();
        mChartData = chartData;
        mItemCount = chartData.size();
        post(new Runnable() {
            @Override
            public void run() {
                if (mMode == MODE_FIXED) {
                    //固定的情况下，不能滑动
                    //获取内容宽度
                    //内容宽度即图表宽度
                    //必须有条目数量和条目宽度
                    //间隙数量是条目数量少1
                    mGapCount = mItemCount - 1;
//                    mItemCount = mGapCount + 1;
                    //间隙宽度
                    //间隙宽度和图表宽度必须有一个是确定的,由它得出另一个
                    //设间隙宽度是条目宽度的3/10

//            mContentWidth = (int) (3f / 10f * mItemWidth);
//            mContentWidth = mItemWidth / 10 * 3;

//            mItemWidth = 10 / 3 * mGapWidth;

//            mContentWidth = mItemCount * 10 / 3 * mContentWidth + (mItemCount - 1) * mContentWidth;
                    //间隙宽度
//                    mGapWidth = mContentWidth / (mItemCount * 10 / 3 + mGapCount);


//                    mGapWidth = mItemWidth / 5;

                    //条目与间距的比例
                    float ratio = 10f / 3f;
////                    mGapWidth = mItemWidth * 3 / 10;
//                    mContentWidth = mGapWidth * mGapCount + (10f / 3f * mGapWidth) * (mGapCount + 1);
//                    mContentWidth = mGapWidth * mGapCount + (ratio * mGapWidth) * (mGapCount + 1);
//                    mContentWidth = mGapWidth * mGapCount + (ratio * mGapWidth) * (mGapCount) + (ratio * mGapWidth);
////                    mContentWidth / mGapWidth = mGapCount + (ratio) * (mGapCount) + (ratio);
////                    mContentWidth / mGapWidth = mGapCount + (ratio) * (mGapCount) + (ratio);
////                    mGapWidth / mContentWidth = 1 / (mGapCount + (ratio) * (mGapCount) + (ratio));
                    float v = mGapCount + ratio * mGapCount + ratio;
                    mGapWidth = mContentWidth / v;
                    int i = mGapCount + 5 * mGapCount + 5;
                    mItemWidth = mGapWidth * ratio;
//
                }
                float maxValue = 0;

                for (int i = 0; i < mChartData.size(); i++) {
                    ChartData data = mChartData.get(i);
                    float value = data.value;
                    maxValue = Math.max(maxValue, value);
                }
                for (int i = 0; i < mChartData.size(); i++) {

                    ChartData data = mChartData.get(i);
                    //值得高度比
                    float ratio = data.value / maxValue;
                    float left = mPaddingLeft + i * mItemWidth + i * mGapWidth;
                    int top = getPaddingTop() + mTextHeight + mTextVerticalSpacing;
                    float right = mPaddingLeft + (i + 1) * mItemWidth + i * mGapWidth;
                    int bottom = mContentHeight - 2 * mTextHeight - mTextVerticalSpacing * 3;
                    RectF e = new RectF(left, top, right, bottom);
                    if (Float.isNaN(ratio)) {
                        e.top = top + e.height();
                    } else {
                        e.top = top + (1 - ratio) * e.height();
                    }
                    mRectFS.add(e);
                }

                if (mUseAnimation) {
                    ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
                    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            mProgress = (float) animation.getAnimatedValue();
                            invalidate();
                        }
                    });
                    animator.setDuration(mAnimationDuration);
                    animator.start();
                } else {
                    invalidate();
                }
            }
        });
    }

    public void setUseAnimation(boolean useAnimation) {
        this.mUseAnimation = useAnimation;
    }

    public void setAnimationDuration(int animationDuration) {
        mAnimationDuration = animationDuration;
    }

    private float downX;
    private float downY;
    private float mHighlightPosition = -1;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                float x = event.getX();
                float y = event.getY();
                if (x == downX && y == downY) {
                    performClick();
                    for (int i = 0; i < mRectFS.size(); i++) {
                        RectF rectF = mRectFS.get(i);
                        if (x > rectF.left && x < rectF.right) {
                            performItemClick(i);
                            break;
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                break;
        }
        return true;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    public void setDefaultSelectedItem(int position) {
        mDefaultSelectedPosition = position;
    }

    public void performItemClick(int position) {
        if (mChartData == null) {
            return;
        }
        highlight(position);
        if (mOnItemBarClickListener != null) {
            if (mSelectPosition == position) {
                mOnItemBarClickListener.onItemRepeatClick(position, mChartData.get(position));
            } else {
                mOnItemBarClickListener.onItemClick(position, mChartData.get(position));
            }
        }
        mSelectPosition = position;
    }

    public void setHighlightPosition(float highlightPosition) {
        mHighlightPosition = highlightPosition;
    }

    private void highlight(int highlightPosition) {
        mHighlightPosition = highlightPosition;
        invalidate();
    }

    /**
     * @param textVerticalSpacing 竖直距离 ，单位px
     */
    public void setTextVerticalSpacing(int textVerticalSpacing) {
        mTextVerticalSpacing = textVerticalSpacing;
    }

    /**
     * @param mode
     */
    public void setMode(int mode) {
        mMode = mode;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mRectFS == null || mRectFS.size() == 0) {
            canvas.drawColor(Color.WHITE);
            return;
        }
        for (int i = 0; i < mRectFS.size(); i++) {
            RectF rectF = mRectFS.get(i);

            if (mHighlightPosition == i) {
                mPaint.setColor(mHighlightColor);
                if (mDrawHighlightShadow) {
                    mShadowPaint.setColor(mHighlightShadowColor);
                    Log.d(this.getClass().getName(), "onDraw: #E4E4E4 " + Integer.toHexString(mHighlightShadowColor));
                    canvas.drawRect(rectF.left, 0, rectF.right, rectF.bottom, mShadowPaint);
                }
            } else {
                mPaint.setColor(mDefaultColor);
                if (mDrawAllShadow) {
                    mShadowPaint.setColor(mShadowColor);
                    Log.d(this.getClass().getName(), "onDraw: #f6f6f6 " + Integer.toHexString(mShadowColor));
                    canvas.drawRect(rectF.left, 0, rectF.right, rectF.bottom, mShadowPaint);
                }
            }
            if (mUseAnimation) {
                //条形图动画变动的是顶部top的值
                //从0到1，从下往上涨top的值必须变得越来越小，直到达到原rectF.top的值
                //最初rectF.top加上rectF.height()是rectF.bottom，变小只需取反进度的值，让高度的值变小，直到rectF.height()为0，那么就是rectF.top的值
                canvas.drawRect(rectF.left, rectF.top + (1 - mProgress) * rectF.height(), rectF.right, rectF.bottom, mPaint);
            } else {
                canvas.drawRect(rectF, mPaint);
            }


            if (i > mChartData.size() - 1) {
                return;
            }
            float textCenter = rectF.width() / 2 + rectF.left;

            ChartData chartData = mChartData.get(i);

            if (mShowValues) {
                float y = rectF.top - mTextPaint.descent() - mTextVerticalSpacing;
                if (mJustShowHighlightValue) {
                    if (i == mHighlightPosition) {
                        if (mUseAnimation) {
                            canvas.drawText(String.valueOf(chartData.stringValue), textCenter, (1 - mProgress) * rectF.height() + y, mTextPaint);
                        } else {
                            canvas.drawText(String.valueOf(chartData.stringValue), textCenter, y, mTextPaint);
                        }
                    }
                } else {
                    if (mUseAnimation) {
                        canvas.drawText(String.valueOf(chartData.stringValue), textCenter, (1 - mProgress) * rectF.height() + y, mTextPaint);
                    } else {
                        canvas.drawText(String.valueOf(chartData.stringValue), textCenter, y, mTextPaint);
                    }
                }
            }

            canvas.drawText(String.valueOf(chartData.date), textCenter, rectF.bottom + Math.abs(mTextPaint.ascent()) + mTextVerticalSpacing, mTextPaint);
            canvas.drawText(String.valueOf(chartData.week), textCenter, rectF.bottom + Math.abs(mTextPaint.ascent()) * 2 + mTextVerticalSpacing * 2, mTextPaint);
        }
    }

    /**
     * 表示动画进行的进度
     */
    private float mProgress;
    private boolean mShowValues;
    private boolean mJustShowHighlightValue;

    public void setJustShowHighlightValue(boolean justShowHighlightValue) {
        mJustShowHighlightValue = justShowHighlightValue;
    }

    public void setShowValues(boolean showValues) {
        this.mShowValues = showValues;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mW = w;
        mH = h;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureDimension(200, widthMeasureSpec);
        int height = measureDimension(200, heightMeasureSpec);

        if (getPaddingStart() != 0) {
            mPaddingLeft = getPaddingStart();
        } else {
            mPaddingLeft = getPaddingLeft();
        }
        if (getPaddingRight() != 0) {
            mPaddingRight = getPaddingEnd();
        } else {
            mPaddingRight = getPaddingRight();
        }
        mPaddingBottom = getPaddingBottom();
        mPaddingTop = getPaddingTop();

        mContentWidth = width - mPaddingLeft - mPaddingRight;
        mContentHeight = height - mPaddingTop - mPaddingBottom;

        setMeasuredDimension(width, height);
        mTextHeight = (int) (Math.abs(mTextPaint.ascent()) + Math.abs(mTextPaint.descent()));
        mGraphHeight = height - mTextHeight * 3;
    }

    public int measureDimension(int defaultSize, int measureSpec) {
        int result;

        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = defaultSize;   //UNSPECIFIED
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }


    int dpToPx(int dps) {
        return Math.round(getResources().getDisplayMetrics().density * dps);
    }

    public interface OnItemBarClickListener {
        void onItemClick(int position, ChartData chartData);

        void onItemRepeatClick(int position, ChartData chartData);

    }

    public static class ChartData {
        private float value;
        private String stringValue;
        private String date;
        private String week;

        public ChartData(float value, String stringValue, String date, String week) {
            this.value = value;
            this.stringValue = stringValue;
            this.date = date;
            this.week = week;
        }

        public String getStringValue() {
            return stringValue;
        }

        public void setStringValue(String stringValue) {
            this.stringValue = stringValue;
        }

        public float getValue() {
            return value;
        }

        public void setValue(float value) {
            this.value = value;
        }

        public String getDate() {
            return date;
        }

        public void setDate(String date) {
            this.date = date;
        }

        public String getWeek() {
            return week;
        }

        public void setWeek(String week) {
            this.week = week;
        }
    }

}